pass :: [Inst] -> [Inst]
pass = peep1 . peep2 . peep3 . removeUnused

peep3 (x1:x2:x3:xs) = case x1 of
    InstMove a b -> case x2 of
                         InstMove c d     | b == c               -> case x3 of
                                                                         InstMove _ f    | b == f -> peep3 $ (InstMove a d):x3:xs
                                                                         InstUn _ _ f    | b == f -> peep3 $ (InstMove a d):x3:xs
                                                                         InstBin _ _ _ f | b == f -> peep3 $ (InstMove a d):x3:xs
                                                                         _ -> x1:(peep3 $ x2:x3:xs)
                         InstMove _ _                            -> case x3 of
                                                                         InstMove e g     | b == g && b == e                   -> peep3 $ x2:(InstMove a g):x3:xs
                                                                         InstUn op e g    | b == g && b == e                   -> peep3 $ x2:(InstUn op a g):x3:xs
                                                                         InstBin op e f g | (b == g) && ((b == e) && (b /= f)) -> peep3 $ x2:(InstBin op a f g):xs
                                                                         InstBin op e f g | (b == g) && ((b /= e) && (b == f)) -> peep3 $ x2:(InstBin op e a g):xs
                                                                         InstBin op e f g | (b == g) && ((b == e) && (b == f)) -> peep3 $ x2:(InstBin op a a g):xs
                                                                         _ -> x1:(peep3 $ x2:x3:xs)
                         InstUn _ c d     | b == c               -> case x3 of
                                                                         InstMove _ f    | b == f -> peep3 $ (InstMove a d):x3:xs
                                                                         InstUn _ _ f    | b == f -> peep3 $ (InstMove a d):x3:xs
                                                                         InstBin _ _ _ f | b == f -> peep3 $ (InstMove a d):x3:xs
                                                                         _ -> x1:(peep3 $ x2:x3:xs)
                         InstBin op c d e | (b == d) && (b /= c) -> case x3 of
                                                                         InstMove _ f    | b == f -> peep3 $ (InstBin op c a e):x3:xs
                                                                         InstUn _ _ f    | b == f -> peep3 $ (InstBin op c a e):x3:xs
                                                                         InstBin _ _ _ f | b == f -> peep3 $ (InstBin op c a e):x3:xs
                                                                         _ -> x1:(peep3 $ x2:x3:xs)
                         InstBin op c d e | (b /= d) && (b == c) -> case x3 of
                                                                         InstMove _ f    | b == f -> peep3 $ (InstBin op a d e):x3:xs
                                                                         InstUn _ _ f    | b == f -> peep3 $ (InstBin op a d e):x3:xs
                                                                         InstBin _ _ _ f | b == f -> peep3 $ (InstBin op a d e):x3:xs
                                                                         _ -> x1:(peep3 $ x2:x3:xs)
                         InstBin op c d e | (b == d) && (b == c) -> case x3 of
                                                                         InstMove _ f    | b == f -> peep3 $ (InstBin op a a e):x3:xs
                                                                         InstUn _ _ f    | b == f -> peep3 $ (InstBin op a a e):x3:xs
                                                                         InstBin _ _ _ f | b == f -> peep3 $ (InstBin op a a e):x3:xs
                                                                         _ -> x1:(peep3 $ x2:x3:xs)
                         _ -> x1:(peep3 $ x2:x3:xs)
    _ -> x1:(peep3 $ x2:x3:xs)

peep3 (x:xs) = x:(peep3 xs)
peep3 [] = []

peep2 (x1:x2:xs) = case x1 of
    InstMove a b -> case x2 of
                         InstMove c d     | (a == d) && (b == c)               -> peep2 $ x1:xs
                         InstMove c d     | (b == c)                           -> peep2 $ renameRegsMove a c d xs
                         InstUn  op c d   | (b == d) && (b == c)               -> peep2 $ (InstUn  op a b  ):xs
                         InstBin op c d e | (b == e) && ((c == b) && (d /= b)) -> peep2 $ (InstBin op a d e):xs
                         InstBin op c d e | (b == e) && ((c /= b) && (d == b)) -> peep2 $ (InstBin op c a e):xs
                         InstBin op c d e | (b == e) && ((c == b) && (d == b)) -> peep2 $ (InstBin op a a e):xs
                         _ -> x1:(peep2 $ x2:xs)
    InstUn op a b -> case x2 of 
                         InstMove c d     | (b == c)                           -> peep2 $ renameRegsUn op a c d xs
                         _ -> x1:(peep2 $ x2:xs)
    InstBin op a b c -> case x2 of 
                         InstMove d e     | (c == d)                           -> peep2 $ renameRegsBin op a b d e xs
                         _ -> x1:(peep2 $ x2:xs)

peep2 (x:xs) = x:(peep2 xs)
peep2 [] = []

peep1 (x1:xs) = case x1 of
    InstMove a b | a == b -> peep1 xs
                 | otherwise -> if doRename
                                   then x1:(renameRegs src dst xs)
                                   else x1:(peep1 xs)
                                where (doRename, src, dst) = chooseReg a b
                                      rename reg = if reg == src
                                                      then dst
                                                      else reg
    _ -> x1:(peep1 xs)